package 遍历器;

import 抽象语法树节点.方法参数;
import 抽象语法树节点.方法定义;
import 抽象语法树节点.编译单元;
import 抽象语法树节点.表达式类.变量引用表达式;
import 抽象语法树节点.表达式类.方法调用表达式;
import 抽象语法树节点.语句类.变量定义语句;
import 抽象语法树节点.语句类.块语句;
import 新版作用域相关.*;

public class 作用域监听器 extends 抽象语法树基础监听器 {

    public 符号表 符号表;

    private 作用域 当前作用域;

    @Override
    public void 进入编译单元(编译单元 节点) {
        符号表 = new 符号表();
        当前作用域 = 符号表.全局作用域;
        System.out.println("初始化全局作用域");
    }

    @Override
    public void 退出编译单元(编译单元 节点) {
        当前作用域 = null;
    }

    @Override
    public void 进入方法定义(方法定义 节点) {
        System.out.println("解析符号:" + 节点.返回值类型.类型名);
        var 返回值类型 = (类型) 当前作用域.解析(节点.返回值类型.类型名);
        var 方法符号 = new 方法符号(节点.名称, 返回值类型, 当前作用域);
        当前作用域.定义(方法符号);
        System.out.println("定义符号:" + 方法符号.名称);
        当前作用域 = 方法符号;
        System.out.println("进入方法作用域:" + 方法符号.名称);
    }

    @Override
    public void 退出方法定义(方法定义 节点) {
        System.out.println("离开方法作用域:" + ((方法符号) 当前作用域).名称);
        当前作用域 = 当前作用域.取父作用域();
    }

    @Override
    public void 进入方法参数(方法参数 节点) {
        System.out.println("解析符号:" + 节点.返回值类型.类型名);
        当前作用域.定义(new 变量符号(节点.名称, (类型) 当前作用域.解析(节点.返回值类型.类型名)));
        System.out.println("定义变量:" + 节点.名称);
    }

    @Override
    public void 进入块语句(块语句 节点) {
        当前作用域 = new 局部作用域(当前作用域);
        System.out.println("进入局部作用域");
    }

    @Override
    public void 退出块语句(块语句 节点) {
        当前作用域 = 当前作用域.取父作用域();
        System.out.println("离开局部作用域");
    }

    @Override
    public void 进入变量定义语句(变量定义语句 节点) {
        System.out.println("解析符号:" + 节点.类型.类型名);
        当前作用域.定义(new 变量符号(节点.名称, (类型) 当前作用域.解析(节点.类型.类型名)));
        System.out.println("定义变量:" + 节点.名称);
    }

    @Override
    public void 进入方法调用表达式(方法调用表达式 节点) {
        System.out.println("解析符号:" + 节点.名称);
        当前作用域.解析(节点.名称);
    }

    @Override
    public void 进入变量引用表达式(变量引用表达式 节点) {
        System.out.println("解析符号:" + 节点.名称);

        if (当前作用域.解析(节点.名称) == null) {
            System.err.println("未定义变量:" + 节点.名称);
        }
    }
}
